'''
Created on Apr 23, 2012

@author: root
'''
from Base import Base
import threading
#import Queue
#import yum
#import tarfile
#import os
from Project import Project
from Role import Role
from Module import Module
from NodeInfo import NodeInfo
from Software2 import Software2
from Node import Node
#from User import User
import csv
from FileOps import FileOps
#import time

class Ganglia(Base):
    
    binName = ""
    binDir = ""
    binPath = ""
    projectName = "ganglia"
    sw =""
    Nodes = []
    Users = []
    clusterName = ""
    project = None
    remoteProjectDir = "/tmp/pachyderm/ganglia"
    gangliaGoldDir = "./conf/config_files/gold/ganglia/"
    gangliaBackupDir = "./conf/config_files/previous/ganglia/"

        
    def BuildProject(self,Nodes):
        
        modCnt = 0
        ''' Define the Project and Add Appropriate Roles '''
        self.LogInfo("Building Ganglia Project for Installation")
        print "    * Build Ganglia Project for Installation"
        #NEED TO CHECK EPEL VERSION FIRST
        if (float((Nodes[0].osVersion).split()[0]) -5 < 1):
            projectConfig = "./conf/project/ganglia-el5.def"
            print "        * RedHat 5.X Detected"
            self.LogInfo("Red Hat 5.x Detected. Using "+projectConfig)

        elif (float((Nodes[0].osVersion).split()[0]) -5 >= 1):
            projectConfig = "./conf/project/ganglia-el6.def"
            print "        * RedHat 6.X Detected"
            self.LogInfo("Red Hat 6.x Detected. Using "+projectConfig)
            
        self.project = Project(self.projectName,"version",self.binPath)
        self.project.AddRole(Role("Ganglia","*"))
        self.project.AddRole(Role("Server","s"))
        self.project.AddRole(Role("Client","c"))
        self.LogInfo("Reading Ganglia Project Definition File")
        try: 
            for row in csv.DictReader(open(projectConfig), 'personality installorder rpm'.split()):
                if (len(row) == 3):
                    personality = row['personality']
                    installOrder = int(row['installorder'])
                    rpm = row['rpm']
                    self.LogInfo(projectConfig+":"+str(row))
                else:
                    self.LogError("Incorrect Number of Parameters in Ganglia Project Definition File.")
                    print "    * ERROR: Incorrect Number of Parameters in Ganglia Project Definition File."
                                  
                for role in self.project.Roles:
                    if (str(personality) == str(role.personality)):
                        for fileName in Software2.swFilenames:
                            if (str(rpm) in str(fileName)):
                                # Work around for circular dependency in apell and aspell-en
                                if ("ASPELL" in str(rpm).upper()):
                                    depsCheck = False
                                else:
                                    depsCheck = True
                                 
                                role.AddModule(Module(fileName,depsCheck,installOrder))
                                self.LogInfo("Add Module: "+str(fileName))
                                modCnt += 1
            self.LogInfo("Completed Reading Ganglia Project Definition File")

        
       
           

        except Exception, err:
            self.LogError("Problem Loading Ganglia Project Definition File")
            return -1
        roleStr=""
        
        for role in self.project.Roles:
            roleStr += (","+role.name)
        roleStr = roleStr[1:]
            
        
        print "        * "+str(len(self.project.Roles))+" Roles Added to Project: "+roleStr
        print "        * "+str(modCnt) +" Modules Added to Project"
        print "    * Building Ganglia Project Complete"
        
        self.LogInfo(str(len(self.project.Roles))+" Roles Added to Project: "+roleStr)
        self.LogInfo(str(modCnt) +" Modules Added to Project")
        self.LogInfo("Building Ganglia Project Complete")
        
         # Add Appropriate Roles to Nodes
        for node in Nodes: 
            roleStr=""
            for personality in node.personalities:
                for role in self.project.Roles:
                    if (str(personality) == str(role.personality)):
                        node.AddRole(role)
                        roleStr += (","+str(role.name))
            roleStr = roleStr[1:]
            print "    * "+ str(node.hostName) + " will be assigned the following roles: "+str(roleStr)
        
        return 0  
      
    def CheckConfig(self,Nodes,Users):
        
        mondNodesSTR=""
        metadNodesSTR=""
        
        ni = NodeInfo(Nodes,Users)
        mondNodes = ni.GetNodes("c")
        for mn in mondNodes: 
            mondNodesSTR = mondNodesSTR + "," + str(mn.hostName)
        mondNodesSTR =  mondNodesSTR[1:]
        
    
        metadNodes =  ni.GetNodes("s")
        for mn in metadNodes: 

            metadNodesSTR = metadNodesSTR + "," + str(mn.hostName)
        metadNodesSTR =  metadNodesSTR[1:]
        
        self.LogInfo("Installation Verification Report")
        self.LogInfo("-----------------------------------------")
        self.LogInfo("Project:             "+str(self.projectName))
        self.LogInfo("Cluster Name:        "+str(self.clusterName))
        self.LogInfo("Server(s)  (gmetad): "+str(metadNodesSTR))
        self.LogInfo("Client(s): (gmond)   "+str(mondNodesSTR))
        print "---------------------------------------------------"
        print "           INSTALLATION VERIFICATION REPORT    "
        print "---------------------------------------------------"
        print "Project:               "+str(self.projectName)
        print "Cluster Name:          "+str(self.clusterName)
        print "Server(s)  (gmetad):   "+str(metadNodesSTR)
        print "Client(s)  (gmond) :   "+str(mondNodesSTR)

    
    def GmondConfig(self,Nodes,Users):
        fileops = FileOps()
        fileops.LocalPush(self.gangliaGoldDir+"gmond.conf",self.gangliaBackupDir+"gmond.conf")
        ''' Find DataSource Line and modify it with Cluster Name '''
        self.LogInfo("Modifying Gold Copy of Ganglia Client Config File (gmond.conf)")
        print "    * Modifying Gold Copy of Ganglia Client Config File (gmond.conf)"
        newLine = []
        ni = NodeInfo(Nodes,Users)
        clusterSection = False
        udpsendSection = False
        udprecvSection = False
        tcpacceptSection = False
        sectionProcessed = False
        try:
            gmondInFile = open("./conf/config_files/gold/ganglia/gmond.conf", "r")
            for line in gmondInFile:
                                     
                if ("cluster {" in str(line)) and (str(line)[0] != '#'):
                    clusterSection = True
                elif ("udp_send_channel {" in str(line)) and (str(line)[0] != '#'):
                    udpsendSection = True    
                elif ("udp_recv_channel {" in str(line)) and (str(line)[0] != '#'):
                    udprecvSection = True      
                                 
                elif ("}" in str(line)) and ((clusterSection) or (udpsendSection) or (udprecvSection)):
                    clusterSection = False
                    udpsendSection = False
                    udprecvSection = False
    
                    sectionProcessed = False
                    
                if (not sectionProcessed):
                    
                    if (clusterSection):
                        newLine.append(line.strip())
                        newLine.append("  name = \""+self.clusterName+"\"")
                        newLine.append("  owner = \"pachyderm\"")
                        newLine.append("  latlong = \"unspecified\"")
                        newLine.append("  url = \"http://"+str(ni.GetNodes("s")[0].hostName)+"/ganglia\"")
                        sectionProcessed = True
                    elif (udpsendSection):
                        newLine.append(line.strip())
                        newLine.append("bind_hostname = yes # Highly recommended, soon to be default.")
                        newLine.append("                     # This option tells gmond to use a source address")
                        newLine.append("                     # that resolves to the machine's hostname.  Without")
                        newLine.append("                     # this, the metrics may appear to come from any")
                        newLine.append("                     # interface and the DNS names associated with")
                        newLine.append("                     # those IPs will be used to create the RRDs.")
                        newLine.append("#mcast_join = 239.2.11.71")
                        newLine.append("host = "+ str(ni.GetNodes("s")[0].hostName))
                        newLine.append("port = 8649")
                        newLine.append("ttl = 1")
                        sectionProcessed = True
                    elif (udprecvSection):
                        newLine.append(line.strip())
                        newLine.append("#mcast_join = 239.2.11.71")
                        newLine.append(" port = 8649")
                        newLine.append("#bind = 239.2.11.71")
                        newLine.append("retry_bind = true")
                        sectionProcessed = True
    
                    else:
                        newLine.append(line.strip())   
        except Exception, err:
            self.LogError("Problem Reading Gold Copy of Ganglia Client Config File (gmond.conf)")
            print "        * ERROR: Problem Reading Gold Copy of Ganglia Client Config File (gmond.conf)"
            return -1
        try:                    
            gmondOutFile = open("./conf/config_files/gold/ganglia/gmond.conf", "w")
            for line in newLine:
                gmondOutFile.write(line.strip()+"\n")  
                self.LogInfo(line.strip())
            gmondOutFile.close()
        except Exception, err:
            self.LogError("Problem Writing Gold Copy of Ganglia Client Config File (gmond.conf)")
            print "        * ERROR: Problem Writing Gold Copy of Ganglia Client Config File (gmond.conf)"
            return -1
        print "    * Completed Modify of Gold Copy of Ganglia Client Config File (gmond.conf)"
        return 0
        
        
    def GmetadConfig(self):
                
      
        ''' Find DataSource Line and modify it with Cluster Name '''
        newLine = []
        self.LogInfo("Modifying Gold Copy of Ganglia Server Config File (gmetad.conf)")
        print "    * Modifying Gold Copy of Ganglia Server Config File (gmetad.conf)"
        try:
            gmetadInFile = open("./conf/config_files/gold/ganglia/gmetad.conf", "r")
            for line in gmetadInFile:
                if ((str(line).strip())[:1] != "#"):
                    if ("data_source" in line):
                        newLine.append("data_source   \""+str(self.clusterName)+"\" localhost")
                    else:
                        newLine.append(line.strip())       
                else:
                    newLine.append(line.strip())       
        except Exception, err:
            self.LogError("Problem Reading Gold Copy of Ganglia Server Config File (gmetad.conf)")
            print "        * ERROR: Problem Reading Gold Copy of Ganglia Server Config File (gmetad.conf)"
            return -1    
        try:
            gmetadOutFile = open("./conf/config_files/gold/ganglia/gmetad.conf", "w")
            for line in newLine:
                gmetadOutFile.write(line.strip()+"\n")  
                self.LogInfo(line.strip())
    
            gmetadOutFile.close()
        except Exception, err:
            self.LogError("Problem Writing Gold Copy of Ganglia Server Config File (gmetad.conf)")
            print "        * ERROR: Problem Writing Gold Copy of Ganglia Server Config File (gmetad.conf)"
            return -1
        print "    * Completed Modify of Gold Copy of Ganglia Server Config File (gmetad.conf)"
        return 0
           
    def PushConfig(self,Nodes,Users):
        ni = NodeInfo(Nodes,Users)
        fileops = FileOps()
        self.SetUsers(Users)

        mondNodes = ni.GetNodes("c")
        metadNodes = ni.GetNodes("s")
        #Push Server Files
        fileops.Push(metadNodes,Users,"./conf/config_files/gold/ganglia/gmetad.conf","/etc/ganglia/gmetad.conf")
        #Push Client Files
        fileops.Push(mondNodes,Users,"./conf/config_files/gold/ganglia/gmond.conf","/etc/ganglia/gmond.conf")

        #INSTALL FIX
        print "    * Modifying Permissions on /var/lib/ganglia"
        self.SSHExec(self.installSudo+"chmod go+w /var/lib/ganglia/dwoo/*",metadNodes[0].hostName,self.installUser,self.installPW)


    def Start(self,Nodes,Users):
        self.ClearReturnQueue()
        startStatus = 0
        threadCount = 0
        startCMD = ""
        Threads = []
        Base.__init__(self)
        self.SetUsers(Users)
      
        print "    * Starting Ganglia Processes on all Cluster Nodes"
        for node in Nodes:
            for role in node.Roles:
                if ("SERVER" in str(role.name).upper()):
                    startCMD = str(self.installSudo) + "service gmetad start ; " + str(self.installSudo) + "service httpd start"
                    self.LogInfo(str(node.hostName)+":"+str(startCMD))
                    self.LogInfo("Starting gmetad and httpd on "+node.hostName)
                    print "        * Starting gmetad and httpd on "+node.hostName
                elif("CLIENT" in str(role.name).upper()):
                    startCMD = str(self.installSudo) + "service gmond start"
                    self.LogInfo(str(node.hostName)+":"+str(startCMD))
                    self.LogInfo("Starting gmond on "+node.hostName)
                    print "        * Starting gmond on "+node.hostName
             
                Threads.append(threading.Thread(target=self.SSHExec,args=(startCMD,node.hostName,self.installUser,self.installPW)))
                Threads[threadCount].daemon=True
                Threads[threadCount].start()
                threadCount = threadCount + 1
        for thread in Threads:
            thread.join()
            (hostName,username,status,results) = self.returnQueue.get()
            
            if (status == 0):
                 self.LogInfo("Started Processes on "+str(hostName)+":"+str(results))
            else:
                  self.LogError("Could Not start process on "+str(hostName)+":"+str(results))
                  print "        * ERROR: Could Not Start Process:"+str(hostName)+":"+str(results)
                  startStatus = -1    
            
            if (startStatus == 0):
                self.LogInfo("All Ganglia Custer Processes Started")
                ni = NodeInfo(Nodes,Users)
                metadNodes = ni.GetNodes("s")

        print "    * All Ganglia Processes Started:  Browse to http://"+str(metadNodes[0].hostName) + "/ganglia"
        return startStatus
            
            
    def LoadNodes(self,configPath):
        self.LogInfo("Loading Ganglia Configuration File")
        try: 
            for row in csv.DictReader(open(configPath), 'hostname ipaddress personality'.split()):
                if (len(row) == 3):
                    hostname = row['hostname'] 
                    ipAddress = row['ipaddress']  
                    personalities = "*" + row['personality']
                    node = Node(hostname,ipAddress,personalities)
                    self.Nodes.append(node)
                    self.LogInfo(row)
                else:
                    self.LogError("Incorrect Number of Parameters in Ganglia Configuration File."+row)
    
                    return -1
            self.LogInfo("Ganglia Configuration File Loaded")
            return 0   
        except Exception, err:
            self.LogError("Problem Loading Ganglia Configuration File")
            return -1
       
   
            
            
            
    def __init__(self,binPath,clusterName,projectName):
       
        Base.__init__(self)
        self.binPath = binPath
        self.clusterName = clusterName
        self.projectName = projectName
        
        ''' Take the entry from the -g entry and parse the components '''
        
        binComponents = self.binPath[1:].split('/')
        self.binName = binComponents[len(binComponents)-1]
        binComponents.remove(self.binName)
        for comp in (binComponents):
            self.binDir = self.binDir + "/" + comp
        print "    * Starting Ganglia Software Install on Cluster: " + clusterName
        self.LogInfo("Starting Ganglia Software Install on Cluster: " + clusterName)
        

        